'use strict';


//  Object Value Equal

exports.isEqual = function isEqual(iLeft, iRight, iDepth) {

    iDepth = iDepth || 1;

    if (!(iLeft && iRight))  return  (iLeft === iRight);


    iLeft = iLeft.valueOf();  iRight = iRight.valueOf();

    if ((typeof iLeft != 'object')  ||  (typeof iRight != 'object'))
        return  (iLeft === iRight);


    var Left_Key = Object.keys(iLeft),  Right_Key = Object.keys(iRight);

    if (Left_Key.length != Right_Key.length)  return false;


    Left_Key.sort();  Right_Key.sort();  --iDepth;

    for (var i = 0, _Key_;  i < Left_Key.length;  i++) {

        _Key_ = Left_Key[i];

        if (_Key_ != Right_Key[i])  return false;

        if (! iDepth) {
            if (iLeft[_Key_] !== iRight[_Key_])  return false;
        } else if (
            ! isEqual.call(this, iLeft[_Key_], iRight[_Key_], iDepth)
        )
            return false;
    }

    return true;
};


//  Object Private Property

Object.prototype.setPrivate = function (key, value) {

    Object.defineProperty(this, `__${key}__`, {
        value:         value,
        enumerable:    false
    });
};


//  Abstract Class

exports.abstractClass = function (constructor, method_list) {

    function Abstract() {

        if (!(this instanceof Abstract)  ||  (this.constructor == Abstract))
            throw TypeError(`"${constructor.name}" is an Abstract Class`);

        return  constructor.apply(this, arguments);
    }

    if (method_list instanceof Array)
        method_list.forEach(function (key) {

            this[ key ] = function () {

                throw TypeError(
                    `Implementation classes of "${constructor.name}" must define "${key}" method`
                );
            };
        }, Abstract.prototype);

    return Abstract;
};


//  Path from Current Working Directory

const Path = require('path');


exports.fromCWD = function () {

    return Path.join.apply(
        Path,  [ ].concat.apply([ process.cwd() ],  arguments)
    );
};


//  Encrypted Random String

exports.randomCode = function (length) {

    var code = Buffer.from(
            +(new Date())  +  (Math.random() + '').slice(2)
        ).toString('base64');

    return  length  ?  code.slice(-length)  :  code;
};